import shaders from "../shaders";
import assert = require("assert");
import {ProgramConfiguration} from "../data/ProgramConfiguration";

export enum DrawMode {
    LINES,
    TRIANGLES
}

export class Program {
  gl: WebGLRenderingContext;
  program: WebGLProgram | null;
  uniforms: {[key: string]: WebGLUniformLocation | null};
  attributes: {[key: string]: number};
  numAttributes: number;

  constructor(gl: WebGLRenderingContext,
      source: {fragmentSource: string, vertexSource: string},
      configuration: ProgramConfiguration,
      showOverdrawInspector: boolean) {
    this.gl = gl;
    this.program = gl.createProgram();

    const defines = configuration.defines().concat(
        `#define DEVICE_PIXEL_RATIO ${window.devicePixelRatio.toFixed(1)}`);
    if (showOverdrawInspector) {
        defines.push("#define OVERDRAW_INSPECTOR;");
    }

    const fragmentSource = defines.concat(shaders.prelude.fragmentSource, source.fragmentSource).join("\n");
    const vertexSource = defines.concat(shaders.prelude.vertexSource, source.vertexSource).join("\n");

    // 创建并编译fragment shader
    const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(fragmentShader, fragmentSource);
    gl.compileShader(fragmentShader);
    assert(gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS), <any>gl.getShaderInfoLog(fragmentShader));
    gl.attachShader(this.program, fragmentShader);

    // 创建并编译vertex shader
    const vertexShader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vertexShader, vertexSource);
    gl.compileShader(vertexShader);
    assert(gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS), <any>gl.getShaderInfoLog(vertexShader));
    gl.attachShader(this.program, vertexShader);

    // Manually bind layout attributes in the order defined by their
    // ProgramInterface so that we don't dynamically link an unused
    // attribute at position 0, which can cause rendering to fail for an
    // entire layer (see #4607, #4728)
    const layoutAttributes = configuration.interface ? configuration.interface.layoutAttributes : [];
    for (let i = 0; i < layoutAttributes.length; i++) {
        gl.bindAttribLocation(this.program, i, layoutAttributes[i].name);
    }

    gl.linkProgram(this.program);
    assert(gl.getProgramParameter(this.program, gl.LINK_STATUS), <any>gl.getProgramInfoLog(this.program));

    this.numAttributes = gl.getProgramParameter(this.program, gl.ACTIVE_ATTRIBUTES);

    this.attributes = {};
    this.uniforms = {};

    for (let i = 0; i < this.numAttributes; i++) {
        const attribute = gl.getActiveAttrib(this.program, i);
        if (attribute) {
            this.attributes[attribute.name] = gl.getAttribLocation(this.program, attribute.name);
        }
    }

    const numUniforms = gl.getProgramParameter(this.program, gl.ACTIVE_UNIFORMS);
    for (let i = 0; i < numUniforms; i++) {
        const uniform = gl.getActiveUniform(this.program, i);
        if (uniform) {
            this.uniforms[uniform.name] = gl.getUniformLocation(this.program, uniform.name);
        }
    }
  }
/*
  draw(gl: WebGLRenderingContext,
    drawMode: DrawMode,
    // layerID: string,
    // layoutVertexBuffer: VertexBuffer,
    // indexBuffer: IndexBuffer,
    // segments: SegmentVector,
    // configuration: ?ProgramConfiguration,
    // dynamicLayoutBuffer: ?VertexBuffer
) {
   const primitiveSize = {
       [gl.LINES]: 2,
       [gl.TRIANGLES]: 3
   }[drawMode];

   for (const segment of segments.get()) {
       const vaos = segment.vaos || (segment.vaos = {});
       const vao = vaos[layerID] || (vaos[layerID] = new VertexArrayObject());

       vao.bind(
           gl,
           this,
           layoutVertexBuffer,
           indexBuffer,
           configuration && configuration.paintVertexBuffer,
           segment.vertexOffset,
           dynamicLayoutBuffer);

       gl.drawElements(
           drawMode,
           segment.primitiveLength * primitiveSize,
           gl.UNSIGNED_SHORT,
           segment.primitiveOffset * primitiveSize * 2);
    }
  }
  */
}